/*
 * Copyright (C) 2004 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.swing.desktop.frame;

import java.awt.EventQueue;
import java.awt.Point;
import java.beans.PropertyVetoException;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JMenuBar;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

import nu.zoom.swing.desktop.preferences.Preferences;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Implementation of a workbench frame.
 * 
 * @author $Author: johan $
 * @version $Revision: 1.9 $
 */
public class InternalWorkbenchFrame extends WorkbenchFrameDelegate {
	private final Log log = LogFactory.getLog(getClass());

	private final JInternalFrame frame;

	private boolean detaching = false;

	private final Desktop desktop;

	InternalWorkbenchFrame(final DetachableWorkbenchFrame owner,
			final JComponent content, final JMenuBar frameMenu,
			final boolean resizable, final boolean maximizable,
			final Preferences preferences, final String preferencesKey,
			final WorkbenchFrames workbenchFrames, final Desktop desktop) {
		super(owner, preferences, preferencesKey, content, frameMenu,
				resizable, maximizable);
		this.desktop = desktop;
		frame = new JInternalFrame("", resizable, true, maximizable);
		if (frameMenu != null) {
			frame.setJMenuBar(frameMenu);
		}
		frame.getContentPane().add(content);
		layoutFrame();
		frame.addInternalFrameListener(new InternalFrameEventDispatcher());
		frame.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
		desktop.addToDesktop(frame);
	}

	private void layoutFrame() {
		Point defaultPosition = desktop.getNextDefaultPosition();
		int desktopwidth = desktop.getMaxWidth();
		int desktopheight = desktop.getMaxHeight();
		FrameVisualPreferences prefs = getFrameVisualPreferencesFromPreferences();
		Integer width = (prefs != null) ? prefs.getWidth() : null;
		Integer height = (prefs != null) ? prefs.getHeight() : null;
		Integer x = (prefs != null) ? prefs.getPositionx() : null;
		Integer y = (prefs != null) ? prefs.getPositiony() : null;

		int xValue;
		int yValue;
		int widthValue;
		int heightValue;

		if ((width == null) || (height == null) || (x == null) || (y == null)) {
			frame.pack();
			widthValue = frame.getWidth();
			heightValue = frame.getHeight();
			xValue = defaultPosition.x;
			yValue = defaultPosition.y;
		} else {
			xValue = x.intValue();
			yValue = y.intValue();
			widthValue = width.intValue();
			heightValue = height.intValue();
		}

		int xAdjusted = xValue;
		int yAdjusted = yValue;
		if ((xAdjusted < 0) || (xAdjusted > desktopwidth)) {
			xAdjusted = defaultPosition.x;
		}
		if ((yAdjusted < 0) || (yAdjusted > desktopheight)) {
			yAdjusted = defaultPosition.y;
		}

		int widthAdjusted = Math.max(widthValue, 40);
		int heightAdjusted = Math.max(heightValue, 40);
		int frameMaxWidth = xAdjusted + (int) (desktopwidth * 0.9);
		int frameMaxHeight = yAdjusted + (int) (desktopheight * 0.9);

		if (widthAdjusted > frameMaxWidth) {
			widthAdjusted = frameMaxWidth;
		}
		if (heightAdjusted > frameMaxHeight) {
			heightAdjusted = frameMaxHeight;
		}
		if (log.isTraceEnabled()) {
			log.trace("Layout frame: x=" + xAdjusted + " y=" + yAdjusted
					+ " width=" + widthAdjusted + " height=" + heightAdjusted);
		}
		frame.setLocation(xAdjusted, yAdjusted);
		frame.setSize(widthAdjusted, heightAdjusted);
		frame.validate();
	}

	class InternalFrameEventDispatcher extends InternalFrameAdapter {

		/*
		 * (non-Javadoc)
		 * 
		 * @see javax.swing.event.InternalFrameAdapter#internalFrameClosed(javax.swing.event.InternalFrameEvent)
		 */
		public void internalFrameClosed(InternalFrameEvent e) {
			if (!EventQueue.isDispatchThread()) {
				throw new IllegalStateException(
						"Internal frame event dispatcher not called in EventQueue DispatchThread");
			}
			if (!detaching) {
				owner.fireFrameClosed();
			}
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see javax.swing.event.InternalFrameAdapter#internalFrameClosing(javax.swing.event.InternalFrameEvent)
		 */
		public void internalFrameClosing(InternalFrameEvent e) {
			if (!EventQueue.isDispatchThread()) {
				throw new IllegalStateException(
						"Internal frame event dispatcher not called in EventQueue DispatchThread");
			}
			owner.dispose();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#dispose()
	 */
	@Override
	void dispose() {
		savePreferences();
		frame.dispose();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#getTitle()
	 */
	@Override
	String getTitle() {
		return frame.getTitle();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#isVisible()
	 */
	@Override
	boolean isVisible() {
		return frame.isVisible();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#moveToFront()
	 */
	@Override
	void moveToFront() {
		if (frame.isIcon()) {
			try {
				frame.setIcon(false);
			} catch (PropertyVetoException e) {
				// Nevermind, this is just a best effort.
			}
		}
		frame.toFront();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#delegateSetIcons(java.util.List)
	 */
	@Override
	void delegateSetIcons(List<ImageIcon> icons) {
		if (icons.size() > 0) {
			frame.setFrameIcon(icons.get(0));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#setTitle(java.lang.String)
	 */
	@Override
	void setTitle(String newTitle) {
		frame.setTitle(newTitle);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#setVisible(boolean)
	 */
	@Override
	void setVisible(boolean visible) {
		frame.setVisible(visible);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.WorkbenchFrameDelegate#disposeOfNativeFrameWithoutCallbacks()
	 */
	@Override
	void savePreferencesAndDisposeOfNativeFrameWithoutCallbacks() {
		detaching = true;
		dispose();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.frame.AbstractWorkbenchFrame#getFrameVisualPreferences()
	 */
	@Override
	protected FrameVisualPreferences getFrameVisualPreferencesFromFrame() {
		FrameVisualPreferences prefs = null;
		if (frame.isIcon()) {
			log.trace("Disposing frame is Iconified, trying to un-iconify it");
			try {
				frame.setIcon(false);
			} catch (PropertyVetoException e) {
			}
		}
		if (!frame.isIcon()) {
			Integer width = new Integer(frame.getWidth());
			Integer height = new Integer(frame.getHeight());
			Point position = frame.getLocation();
			Integer x = new Integer(position.x);
			Integer y = new Integer(position.y);
			prefs = new FrameVisualPreferences(width, height, x, y);
		}
		return prefs;
	}
}